﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition;

namespace Steve.UI.Extensions
{
    /// <remarks>
    /// This is not a very sophisticated implementation, ignores expiration since its per request,
    /// this is more for debugging than runtime and should not be used in a runtime environment, 
    /// some distributed caching mechanism should be used instead or if its single server then the 
    /// HttpContextCacheService should be used.
    /// </remarks>
    [Export(typeof(ICacheService))]
    [PartCreationPolicy(CreationPolicy.Shared)]
    public sealed class PerRequestCacheService : ICacheService
    {
        [Import]
        public IHttpContextBaseBuilder ContextBuilder { get; set; }

        private static string CreateKey(CacheType cacheType, string cacheKey)
        {
            return string.Format("cache_{0:f}_{1}", cacheType, cacheKey);
        }

        public IEnumerable<string> GetKeys(CacheType cacheType)
        {
            var ctx = ContextBuilder.BuildCurrent();
            var test = string.Format("cache_{0:f}_", cacheType);

            if (ctx == null) yield break;

            foreach (var key in ctx.Items.Keys)
            {
                var sKey = key as string;

                if (string.IsNullOrWhiteSpace(sKey)) continue;

                if (sKey.StartsWith(test)) yield return sKey.Substring(test.Length);    
            }
        }

        public T GetValue<T>(CacheType cacheType, string cacheKey) where T : class
        {
            var ctx = ContextBuilder.BuildCurrent();

            if (ctx == null) return null;

            return (T)ctx.Items[CreateKey(cacheType, cacheKey)];
        }

        public void PutValue(CacheType cacheType, string cacheKey, object value, TimeSpan? ttl)
        {
            var ctx = ContextBuilder.BuildCurrent();

            if (ctx == null) return;

            ctx.Items[CreateKey(cacheType, cacheKey)] = value;
        }

        public void Invalidate(CacheType cacheType, string cacheKey)
        {
            var ctx = ContextBuilder.BuildCurrent();

            if (ctx == null) return;

            ctx.Items.Remove(CreateKey(cacheType, cacheKey));
        }

        public void Invalidate(CacheType cacheType)
        {
            var ctx = ContextBuilder.BuildCurrent();

            if (ctx == null) return;

            var prefix = CreateKey(cacheType, string.Empty);
            var items = ctx.Items;
            var query = from k in items.Keys.OfType<string>()
                        where k.StartsWith(prefix, StringComparison.Ordinal)
                        select k;

            var toRemove = query.ToList();

            foreach (var k in toRemove)
            {
                items.Remove(k);
            }
        }


    }
}
